////////////////////////////////////////////////////////////////////////////
//
//  CryEngine Source File.
//  Copyright (C), Crytek, 1999-2010.
// -------------------------------------------------------------------------
//  File name:	AssetTextureDatabase.cpp
//  Version:	v1.00
//  Created:	15/04/2009 by Paulo Zaffari
//  Description:	Implementation of AssetTextureDatabase.h
// -------------------------------------------------------------------------  
//  History:
//		15/04/2009	11:00 - Paulo Zaffari - created
//		12/03/2010	17:16 - Nicusor Nedelcu - refactored
//
//////////////////////////////////////////////////////////////////////////// 

#include "stdafx.h"
#include "AssetTextureDatabase.h"
#include "AssetTextureItem.h"
#include "ITexture.h"
#include "IRenderer.h"
#include "ImageExtensionHelper.h"
#include "Include/IAssetViewer.h"
#include "StringUtils.h"
#include "Util/IndexedFiles.h"

REGISTER_CLASS_DESC(CAssetTextureDatabase);

CAssetTextureDatabase::CAssetTextureDatabase() : CAssetDisplayDatabase()
{
	// add fields
	static const int kFilenameColWidth = 150;
	static const int kDccFilenameColWidth = 50;
	static const int kFileSizeColWidth = 50;
	static const int kRelativePathColWidth = 50;
	static const int kWidthColWidth = 50;
	static const int kHeightColWidth = 50;
	static const int kMipsColWidth = 50;
	static const int kFormatColWidth = 100;
	static const int kTypeColWidth = 50;
	static const int kUsedInLevelColWidth = 40;
	static const int kLoadedInLevelColWidth = 40;
	static const int kTagsColWidth = 60;

	m_assetFields.push_back( SAssetField( "filename", "Filename", SAssetField::eAssetFieldType_String, kFilenameColWidth ) );
	m_assetFields.push_back( SAssetField( "filesize", "Filesize (KB)", SAssetField::eAssetFieldType_Int32, kFileSizeColWidth ) );
	m_assetFields.push_back( SAssetField( "relativepath", "Path", SAssetField::eAssetFieldType_String, kRelativePathColWidth ) );
	m_assetFields.push_back( SAssetField( "width", "Width", SAssetField::eAssetFieldType_Int32, kWidthColWidth ) );
	m_assetFields.push_back( SAssetField( "height", "Height", SAssetField::eAssetFieldType_Int32, kHeightColWidth ) );
	m_assetFields.push_back( SAssetField( "mips", "MipCount", SAssetField::eAssetFieldType_Int32, kMipsColWidth ) );
	m_assetFields.push_back( SAssetField( "format", "Format", SAssetField::eAssetFieldType_String, kFormatColWidth ) );
	m_assetFields.push_back( SAssetField( "type", "Type", SAssetField::eAssetFieldType_String, kTypeColWidth ) );
	m_assetFields.push_back( SAssetField( "usedinlevel", "Used in level", SAssetField::eAssetFieldType_Bool, kUsedInLevelColWidth ) );
	m_assetFields.push_back( SAssetField( "loadedinlevel", "Loaded in level", SAssetField::eAssetFieldType_Bool, kLoadedInLevelColWidth ) );
	m_assetFields.push_back( SAssetField( "dccfilename", "DCC Filename", SAssetField::eAssetFieldType_String, kDccFilenameColWidth ) );
	m_assetFields.push_back( SAssetField( "tags", "Tags", SAssetField::eAssetFieldType_String, kTagsColWidth ) );

	{
		SAssetField* pField = GetAssetFieldByName( "width" );
		
		pField->m_bUseEnumValues = true;
		pField->m_enumValues.push_back( "4" );
		pField->m_enumValues.push_back( "8" );
		pField->m_enumValues.push_back( "16" );
		pField->m_enumValues.push_back( "32" );
		pField->m_enumValues.push_back( "64" );
		pField->m_enumValues.push_back( "128" );
		pField->m_enumValues.push_back( "256" );
		pField->m_enumValues.push_back( "512" );
		pField->m_enumValues.push_back( "1024" );
		pField->m_enumValues.push_back( "2048" );
	}

	{
		SAssetField* pField = GetAssetFieldByName( "height" );

		pField->m_bUseEnumValues = true;
		pField->m_enumValues.push_back( "4" );
		pField->m_enumValues.push_back( "8" );
		pField->m_enumValues.push_back( "16" );
		pField->m_enumValues.push_back( "32" );
		pField->m_enumValues.push_back( "64" );
		pField->m_enumValues.push_back( "128" );
		pField->m_enumValues.push_back( "256" );
		pField->m_enumValues.push_back( "512" );
		pField->m_enumValues.push_back( "1024" );
		pField->m_enumValues.push_back( "2048" );
	}

	{
		SAssetField* pField = GetAssetFieldByName( "mips" );

		pField->m_bUseEnumValues = true;
		pField->m_enumValues.push_back( "1" );
		pField->m_enumValues.push_back( "2" );
		pField->m_enumValues.push_back( "3" );
		pField->m_enumValues.push_back( "4" );
		pField->m_enumValues.push_back( "5" );
		pField->m_enumValues.push_back( "6" );
		pField->m_enumValues.push_back( "7" );
		pField->m_enumValues.push_back( "8" );
		pField->m_enumValues.push_back( "9" );
		pField->m_enumValues.push_back( "10" );
	}
}

CAssetTextureDatabase::~CAssetTextureDatabase()
{
	// emtpty, call FreeData() first
}

//////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE CAssetTextureDatabase::QueryInterface( const IID &riid, void **ppvObj ) 
{ 
	if(riid == __uuidof(IAssetDisplayDatabase)/* && m_pIntegrator*/)
	{
		*ppvObj = this;
		return S_OK;
	}
	return E_NOINTERFACE ; 
}

const char* CAssetTextureDatabase::GetDatabaseTypeExt() const
{
	return "dds"; 
};

const char* CAssetTextureDatabase::GetDatabaseName() const
{
	return "Textures";
}

void CAssetTextureDatabase::Refresh()
{
	FreeData();

	const char						*szTextureName = NULL;
	CString								strExtension;
	CString								strFilename;
	CFileUtil::FileArray	cFiles;
	int										nTotalFiles = 0;
	int										nCurrentFile = 0;
	CString								strIntermediateFilename;
	CString								strOutputTextureName, strPathOnly, strFileNameOnly;
	CCryFile							file;
	CAssetTextureItem*		poTextureDatabaseItem = NULL;

	// search for DDS files
	std::vector<CString> tags; 
	
	tags.push_back("dds");
	CIndexedFiles::GetDB().GetFilesWithTags(cFiles, tags);

	// for every file, check if is a texture...
	nTotalFiles = cFiles.size();

	for( nCurrentFile = 0; nCurrentFile < nTotalFiles; ++nCurrentFile )
	{
		CFileUtil::FileDesc& rstFileDescriptor = cFiles[nCurrentFile];
		strIntermediateFilename = rstFileDescriptor.filename.GetBuffer();
		strIntermediateFilename.MakeLower();
		Path::ConvertBackSlashToSlash(strIntermediateFilename);
		strOutputTextureName = strIntermediateFilename;
	
		if( Path::GetExt(strOutputTextureName) != "dds" )
			continue;

		// no need for temp files.
		if( strstr( rstFileDescriptor.filename, "~~~TempFile~~~" ) != NULL )
		{
			continue;
		}

		poTextureDatabaseItem = new CAssetTextureItem();

		if( !poTextureDatabaseItem )
			return;

		strFileNameOnly = Path::GetFile( strOutputTextureName );
		strPathOnly = Path::GetPath( strOutputTextureName );
		strExtension = Path::GetExt( strOutputTextureName.GetBuffer() );

		poTextureDatabaseItem->SetFileSize( rstFileDescriptor.size );
		poTextureDatabaseItem->SetFilename( strFileNameOnly.GetBuffer() );
		poTextureDatabaseItem->SetRelativePath( strPathOnly.GetBuffer() );
		poTextureDatabaseItem->SetOwnerDisplayDatabase( this );
		poTextureDatabaseItem->SetFileExtension( strExtension.GetBuffer() );
		poTextureDatabaseItem->SetFlag( IAssetDisplay::eAssetFlags_Visible, true );
		m_assets[strOutputTextureName.GetBuffer()] = poTextureDatabaseItem;
	}

	// clear up the file array
	cFiles.clear();
	tags.clear();
	tags.push_back("tif");
	CIndexedFiles::GetDB().GetFilesWithTags(cFiles, tags);

	// for every file, check if is a texture...
	nTotalFiles = cFiles.size();

	for( nCurrentFile = 0; nCurrentFile < nTotalFiles; ++nCurrentFile )
	{
		CFileUtil::FileDesc& rstFileDescriptor = cFiles[nCurrentFile];
		strIntermediateFilename = rstFileDescriptor.filename.GetBuffer();
		strIntermediateFilename.MakeLower();
		Path::ConvertBackSlashToSlash(strIntermediateFilename);
		strOutputTextureName = strIntermediateFilename;
		if( Path::GetExt(strOutputTextureName) != "tif" )
			continue;

		// no need for temp files.
		if( strstr( strOutputTextureName.GetBuffer(), "~~~TempFile~~~" ) != NULL )
		{
			continue;
		}

		strFilename = strOutputTextureName.GetBuffer();
		strExtension = Path::GetExt( strOutputTextureName.GetBuffer() );
		strFilename = Path::ReplaceExtension( strFilename, "dds" );

		// textures without names are not important for us.
		szTextureName = (char*)rstFileDescriptor.filename.GetBuffer();

		if( !szTextureName )
		{
			continue;
		}

		// textures which name starts with '$' are dynamic textures or in any way textures that
		// don't interest us.
		if( szTextureName[0] == '$' )
		{
			continue;
		}

		strFileNameOnly = Path::GetFile( strOutputTextureName );
		strPathOnly = Path::GetPath( strOutputTextureName );

		poTextureDatabaseItem = new CAssetTextureItem();

		if( !poTextureDatabaseItem )
			return;

		poTextureDatabaseItem->SetFileSize( rstFileDescriptor.size );
		poTextureDatabaseItem->SetFilename( strFileNameOnly.GetBuffer() );
		poTextureDatabaseItem->SetRelativePath( strPathOnly.GetBuffer() );
		poTextureDatabaseItem->SetOwnerDisplayDatabase( this );
		poTextureDatabaseItem->SetFileExtension( strExtension.GetBuffer() );
		poTextureDatabaseItem->SetFlag( IAssetDisplay::eAssetFlags_Visible, true );
		m_assets[strIntermediateFilename.GetBuffer()] = poTextureDatabaseItem;
	}
}

void CAssetTextureDatabase::CacheFieldsInfoForAlreadyLoadedAssets()
{
	ISystem *pSystem = GetISystem();
	IRenderer *pRenderer = pSystem->GetIRenderer();

	int nTexCount = *(int*)pRenderer->EF_Query(EFQ_GetAllTextures,0);
	if (nTexCount > 0)
	{
		std::vector<ITexture*> pTextures;
		pTextures.resize(nTexCount);
		pRenderer->EF_Query( EFQ_GetAllTextures,(INT_PTR)&pTextures[0] );
		for (int i = 0; i < nTexCount; ++i)
		{
			ITexture *pTexture = pTextures[i];
			int nTexSize = pTexture->GetDataSize();
			if (nTexSize > 0)
			{
				CString textureName = pTexture->GetName();
				Path::ConvertSlashToBackSlash(textureName);
				TFilenameAssetMap::iterator itr = m_assets.find(textureName.GetBuffer());
				if ( m_assets.end() != itr )
				{
					itr->second->SetFlag( IAssetDisplay::eAssetFlags_UsedInLevel, true );
					static_cast<CAssetTextureItem*>(itr->second)->CacheFieldsInfoForLoadedTex(pTexture);
				}
			}
		}
	}
}

const char* CAssetTextureDatabase::GetTransactionFilename() const
{
	return "textureAssetTransactions.xml";
}

void CAssetTextureDatabase::PrecacheFieldsInfoFromFileDB(const XmlNodeRef& db)
{
	assert(db->isTag(GetDatabaseName()));
	for(int i=0; i<db->getChildCount(); ++i)
	{
		XmlNodeRef entry = db->getChild(i);
		CString fileName = entry->getAttr("fileName");
		TFilenameAssetMap::iterator assetIt = m_assets.find(fileName);
		bool bAssetFound = m_assets.end() != assetIt;
		if(bAssetFound)
			assetIt->second->FromXML(entry);
	}
}
